package com.cbh.amadeus.common.protocol;

import com.cbh.amadeus.common.exception.ProtocolMagicMatchException;
import com.cbh.amadeus.common.json.Json;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @author ChenBiHui
 * @date 2025/4/25
 */
public class AmadeusMessageProtocol extends ByteToMessageCodec<AmadeusMessageWrap> {

    public static final Integer MAGIC = 1163020611;

    public static LengthFieldBasedFrameDecoder frameDecoder() {
        return new LengthFieldBasedFrameDecoder(
                10 * 1024 * 1024,
                14,
                4,
                0,
                0
        );
    }

    public static AmadeusMessageProtocol protocol() {
        return new AmadeusMessageProtocol();
    }

    @Override
    protected void encode(ChannelHandlerContext ctx, AmadeusMessageWrap msg, ByteBuf out) {
        int magic = msg.getMagic();
        if (!MAGIC.equals(magic)) {
            throw new ProtocolMagicMatchException("Protocol magic not match");
        }
        byte type = msg.getType();
        byte approach = msg.getApproach();
        long achieve = msg.getAchieve();
        AmadeusMessage message = msg.getMessage();
        byte[] payload = Json.toJson(message).getBytes(StandardCharsets.UTF_8);
        out.writeInt(magic);
        out.writeByte(type);
        out.writeByte(approach);
        out.writeLong(achieve);
        out.writeInt(payload.length);
        out.writeBytes(payload);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        int magic = in.readInt();
        if (!MAGIC.equals(magic)) {
            throw new ProtocolMagicMatchException("Protocol magic not match");
        }
        byte type = in.readByte();
        byte approach = in.readByte();
        long achieve = in.readLong();
        int length = in.readInt();
        ByteBuf byteBuf = null;
        try {
            byteBuf = in.readBytes(length);
            String message = byteBuf.toString(StandardCharsets.UTF_8);
            AmadeusMessageWrap change = new AmadeusMessageWrap();
            change.setMagic(magic);
            change.setType(type);
            change.setApproach(approach);
            change.setAchieve(achieve);
            change.setMessage(Json.parse(message));
            out.add(change);
        } finally {
            if (byteBuf != null) {
                byteBuf.release();
            }
        }
    }
}
